Next | Prev | Up | Top | Contents | Index

Using Precompiled Headers in C and C++

This section describes the precompiled header mechanism that is available with the n32-bit and 64-bit C and C++ compilers. For information on the 32-bit precompiled header mechanism for C++ available with the Smart Build utility, see the C++ Programming Guide.

This section contains the following topics:


About Precompiled Headers

The precompiled header (PCH) file mechanism is available through the compiler front end: fec and fecc. Use PCH to avoid recompiling a set of header files. This is particularly useful when your header files introduce many lines of code, and the primary source files that included them are relatively small.

In effect, fec/fecc takes a snapshot of the state of the compilation at a particular point and writes it to a file before completing the compilation. When you recompile the same source file or another file with the same set of header files, the PCH mechanism recognizes the snapshot point, verifies that the corresponding PCH file is usable, and reads it back in.

The PCH mechanism can give you a dramatic improvement in compile-time performance. The trade-off is that PCH files may take a lot of disk space.


Automatic Precompiled Header Processing

This section covers the following topics:

You can enable the precompiled header processing by using the -pch option on the command line. With the PCH mechanism enabled, fec/fecc searches for a qualifying PCH file to read in and/or creates one for use on a subsequent compilation.

The PCH file contains a snapshot of all the code preceding the header stop point. The header stop point is typically the first token in the primary source file that does not belong to a preprocessing directive. The header stop point can also be specified directly by inserting a #pragma hdrstop. For example, consider the following C++ code:

#include "xxx.h"
#include "yyy.h"
int i;
In this case, the header stop point is int i (the first non-preprocessor token) and the PCH file will contain a snapshot reflecting the inclusion of xxx.h and yyy.h. If the first non-preprocessor token or the #pragma hdrstop appears within a #if block, the header stop point is the outermost enclosing #if. For example, consider the following C++ code:

#include "xxx.h"
#ifndef YYY_H
#define YYY_H 1
#include "yyy.h"
#endif
#if TEST
int i;
#endif
In this case, the first token that does not belong to a preprocessing directive is again int i, but the header stop point is the start of the #if block containing the int. The PCH file reflects the inclusion of xxx.h and conditionally the definition of YYY_H and inclusion of yyy.h. The file does not contain the state produced by #if TEST.

PCH File Requirements

A PCH file is produced only if the header stop point and the code preceding it (generally the header files themselves) meet the following requirements:

Reusing PCH Files

When a precompiled header file is produced, in addition to the snapshot of the compiler state, it contains some information that can be checked to determine under what circumstances it can be reused. This information includes the following:

This information comprises the PCH prefix. The prefix information of a given source file can be compared to the prefix information of a PCH file to determine whether or not the latter is applicable to the current compilation.

For example, consider the following C++ code:

// a.C 
#include "xxx.h" 

...              // Start of code

// b.C 
#include "xxx.h" 

...              // Start of code
When you compiled a.C with the -pch option, the PCH file a.pch is created. When you compile b.C (or recompile a.C), the prefix section of a.pch is read in for comparison with the current source file. If the command line options are identical and xxx.h has not been modified, fec/fecc reads in the rest of a.pch rather than opening xxx.h and processing it line by line. This establishes the state for the rest of the compilation.

It may be that more than one PCH file is applicable to a given compilation. If so, the largest (in other words, the one representing the most preprocessing directives from the primary source file) is used. For instance, consider a primary source file that begins with the following code:

#include "xxx.h" 
#include "yyy.h" 
#include "zzz.h"
If one PCH file exists for xxx.h and a second for xxx.h and yyy.h, the latter will be selected (assuming both are applicable to the current compilation). After the PCH file for the first two headers is read in and the third is compiled, a new PCH file for all three headers may be created.

When a precompiled header file is created, it takes the name of the primary source file, with the suffix replaced by "pch." Unless -pch_dir is specified, the PCH file is created in the directory of the primary source file.

When a precompiled header file is created or used, a message similar to the following is issued:

"test.C": creating precompiled header file "test.pch"

Obsolete File Deletion Mechanism

In automatic mode (when -pch is used), fec/fecc considers a PCH file obsolete and deletes it under the following circumstances:

You must manually clean up any other PCH file.

Support for PCH processing is not available when multiple source files are specified in a single compilation. If the command line includes a request for precompiled header processing and specifies more than one primary source file, an error is issued and the compilation is aborted.


Other Ways to Control Precompiled Headers

You can use the following ways to control and/or tune how precompiled headers are created and used:


PCH Performance Issues

The relative overhead incurred in writing out and reading back in a precompiled header file is quite small for reasonably large header files.

In general, writing out a precompiled header file doesn't cost much, even if it does not end up being used, and if it is used it almost always produces a significant speedup in compilation. The problem is that the precompiled header files can be quite large (from a minimum of about 250K bytes to several megabytes or more), and so you probably don't want many of them sitting around.

You can see that, despite the faster recompilations, precompiled header processing is not likely to be justified for an arbitrary set of files with nonuniform initial sequences of preprocessing directives. The greatest benefit occurs when a number of source files can share the same PCH file. The more sharing, the less disk space is consumed. With sharing, the disadvantage of large precompiled header files can be minimized without giving up the advantage of a significant speedup in compilation times.

To take full advantage of header file precompilation, you should reorder the #include sections of your source files and/or group the #include directives within a commonly used header file.

The fecc source provides an example of how this can be done. A common idiom is the following:

#include "fe_common.h" 
#pragma hdrstop 
#include ...
In this example, fe_common.h pulls in (directly and indirectly) a few dozen header files. The #pragma hdrstop is inserted to get better sharing with fewer PCH files. The PCH file produced for fe_common.h is slightly over a megabyte in size. Another example, used by the source files involved in declaration processing, is the following:

#include "fe_common.h" 
#include "decl_hdrs.h"
#pragma hdrstop 
#include ...
decl_hdrs.h pulls in another dozen header files, and a second, somewhat larger, PCH file is created. In all, the fifty-odd source files of fecc share just six precompiled header files. If disk space is at a premium, you can decide to make fe_common.h pull in all the header files used. In that case, a single PCH file can be used in building fecc.

Different environments and different projects have different needs. You should, however, be aware that making the best use of the precompiled header support will require some experimentation and probably some minor changes to your source code.


Next | Prev | Up | Top | Contents | Index